package com.atguigu.springcloud.cloudsentinelgatewaydevelop.service.impl;

import com.atguigu.springcloud.cloudsentinelgatewaydevelop.bean.DO.SentinelSystemRuleDO;
import com.atguigu.springcloud.cloudsentinelgatewaydevelop.bean.dto.SentinelSystemRuleDTO;
import com.atguigu.springcloud.cloudsentinelgatewaydevelop.constants.TableNameConstants;
import com.atguigu.springcloud.cloudsentinelgatewaydevelop.mapper.SystemRuleMapper;
import com.atguigu.springcloud.cloudsentinelgatewaydevelop.service.SystemRuleService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.r2dbc.spi.ConnectionFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.data.r2dbc.core.DatabaseClient;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;

import static org.springframework.data.r2dbc.query.Criteria.where;

/**
 * xx
 *
 * @author BugFree Jin
 * @version 1.0
 * @since 2022/3/3 10:27
 */
@Service
@RequiredArgsConstructor
public class SystemRuleServiceImpl implements SystemRuleService {

    private final SystemRuleMapper systemRuleMapper;
    private final ConnectionFactory connectionFactory;

    private DatabaseClient client;

    @PostConstruct
    void init() {
        this.client = DatabaseClient.create(connectionFactory);
    }

    private SentinelSystemRuleDO copyFiled(SentinelSystemRuleDTO sentinelSystemRuleDTO) {
        SentinelSystemRuleDO sentinelSystemRuleDO = new SentinelSystemRuleDO();
        SentinelSystemRuleDO.SystemRule systemRule = new SentinelSystemRuleDO.SystemRule();
        BeanUtils.copyProperties(sentinelSystemRuleDTO, sentinelSystemRuleDO, "system_rule");
        BeanUtils.copyProperties(sentinelSystemRuleDTO,systemRule);
        String systemRuleStr = "";
        try {
            systemRuleStr = new ObjectMapper().writeValueAsString(systemRule);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        sentinelSystemRuleDO.setSystemRule(systemRuleStr);
        return sentinelSystemRuleDO;
    }

    @Override
    public Mono<Integer> save(SentinelSystemRuleDTO sentinelSystemRuleDTO) {
        SentinelSystemRuleDO sentinelSystemRuleDO = copyFiled(sentinelSystemRuleDTO);
        return client.insert()
                .into(TableNameConstants.SYSTEMRULE)
                .nullValue("id", Long.class)
                .value("application_name", sentinelSystemRuleDO.getApplicationName())
                .value("resource", sentinelSystemRuleDO.getResource())
                .value("system_rule", sentinelSystemRuleDO.getSystemRule())
                .fetch()
                .rowsUpdated();
    }

    @Override
    public Mono<Integer> deleteById(Long id) {
        return systemRuleMapper.deleteByID(id);
    }

    @Override
    public Mono<Integer> deleteByAyApplicationName(String applicationName) {
        return systemRuleMapper.deleteByAyApplicationName(applicationName);
    }

    @Override
    public Mono<Integer> updateById(SentinelSystemRuleDTO sentinelSystemRuleDTO, Long id) {
        SentinelSystemRuleDO sentinelSystemRuleDO = copyFiled(sentinelSystemRuleDTO);

        return client.update()
                .table(SentinelSystemRuleDO.class)
                .using(sentinelSystemRuleDO)
                .matching(where("id").is(id))
                .fetch()
                .rowsUpdated();
    }

    @Override
    public Mono<SentinelSystemRuleDTO> findById(Long id) {
        return client.select()
                .from(TableNameConstants.SYSTEMRULE)
                .matching(where("id").is(id))
                .as(SentinelSystemRuleDO.class)
                .fetch()
                .one()
                .map(SentinelSystemRuleDO::getSentinelSystemRuleDTO);
    }

    @Override
    public Flux<SentinelSystemRuleDTO> findByApplicationName(String applicationName) {
        return client.select()
                .from(TableNameConstants.SYSTEMRULE)
                .matching(where("application_name").is(applicationName))
                .as(SentinelSystemRuleDO.class)
                .fetch()
                .all()
                .map(SentinelSystemRuleDO::getSentinelSystemRuleDTO)
                .log();
    }
}
